ํ๋ก ํธ์๋ WebRTC ์ฝ๋ฑ ํ์์ ๋ํ ์ข ํฉ ๊ฐ์ด๋. SDP, ์ ํธ ์ฝ๋ฑ, ๋ธ๋ผ์ฐ์ ํธํ์ฑ ๋ฐ ์ค์๊ฐ ํต์ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ต์ ์ ์ค๋์ค/๋น๋์ค ํ์ง์ ์ํ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ค๋ฃน๋๋ค.
ํ๋ก ํธ์๋ WebRTC ์ฝ๋ฑ ์ ํ: ๋ฏธ๋์ด ์ฝ๋ฑ ํ์ ๋ง์คํฐํ๊ธฐ
WebRTC(Web Real-Time Communication)๋ ์น ๋ธ๋ผ์ฐ์ ๋ด์์ ์ง์ ์ค์๊ฐ ์ค๋์ค ๋ฐ ๋น๋์ค๋ฅผ ๊ฐ๋ฅํ๊ฒ ํ์ฌ ์จ๋ผ์ธ ํต์ ์ ํ๋ช ์ ์ผ์ผ์ผฐ์ต๋๋ค. ๊ทธ๋ฌ๋ ๋ค์ํ ๋คํธ์ํฌ ์กฐ๊ฑด๊ณผ ์ฅ์น์์ ์ต์ ์ ํต์ ํ์ง์ ๋ฌ์ฑํ๋ ค๋ฉด ๋ฏธ๋์ด ์ฝ๋ฑ๊ณผ ๊ทธ ํ์ ๊ณผ์ ์ ๋ํ ์ ์คํ ๊ณ ๋ ค๊ฐ ํ์ํฉ๋๋ค. ์ด ์ข ํฉ ๊ฐ์ด๋๋ ํ๋ก ํธ์๋ WebRTC ์ฝ๋ฑ ์ ํ์ ๋ณต์ก์ฑ์ ์ฌ์ธต์ ์ผ๋ก ๋ค๋ฃจ๋ฉฐ, SDP(Session Description Protocol)์ ๊ธฐ๋ณธ ์๋ฆฌ, ์ ํธ ์ฝ๋ฑ ๊ตฌ์ฑ, ๋ธ๋ผ์ฐ์ ํธํ์ฑ ๋ฏธ๋ฌํจ, ๊ทธ๋ฆฌ๊ณ ์ ์ธ๊ณ ์ฌ์ฉ์์๊ฒ ์ํํ๊ณ ๊ณ ํ์ง์ ์ค์๊ฐ ๊ฒฝํ์ ๋ณด์ฅํ๊ธฐ ์ํ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ํ๊ตฌํฉ๋๋ค.
WebRTC์ ์ฝ๋ฑ ์ดํดํ๊ธฐ
WebRTC๋ ๋ธ๋ผ์ฐ์ ๊ฐ ์ค๊ฐ ์๋ฒ ์์ด(์ด๊ธฐ ์ฐ๊ฒฐ ์ค์ ์ ์ํด ์๊ทธ๋๋ง ์๋ฒ๊ฐ ์ฌ์ฉ๋๊ธฐ๋ ํ์ง๋ง) ์ง์ P2P(peer-to-peer)๋ก ํต์ ํ ์ ์๋๋ก ํฉ๋๋ค. WebRTC์ ํต์ฌ์ ์ค๋์ค ๋ฐ ๋น๋์ค ์คํธ๋ฆผ์ ์ธ์ฝ๋ฉ(์์ถ)ํ๊ณ ๋์ฝ๋ฉ(์์ถ ํด์ )ํ์ฌ ์ธํฐ๋ท์ ํตํด ์ ์กํ๊ธฐ์ ์ ํฉํ๊ฒ ๋ง๋๋ ๋ฅ๋ ฅ์ ๋๋ค. ๋ฐ๋ก ์ด ์ง์ ์์ ์ฝ๋ฑ์ด ์ฌ์ฉ๋ฉ๋๋ค. ์ฝ๋ฑ(coder-decoder)์ ์ด๋ฌํ ์ธ์ฝ๋ฉ ๋ฐ ๋์ฝ๋ฉ ํ๋ก์ธ์ค๋ฅผ ์ํํ๋ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค. ์ฝ๋ฑ์ ์ ํ์ ๋์ญํญ ์ฌ์ฉ๋, ์ฒ๋ฆฌ ๋ฅ๋ ฅ, ๊ทธ๋ฆฌ๊ณ ๊ถ๊ทน์ ์ผ๋ก ์ค๋์ค ๋ฐ ๋น๋์ค ์คํธ๋ฆผ์ ์ฒด๊ฐ ํ์ง์ ์๋นํ ์ํฅ์ ๋ฏธ์นฉ๋๋ค.
๊ณ ํ์ง WebRTC ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค๊ธฐ ์ํด์๋ ์ฌ๋ฐ๋ฅธ ์ฝ๋ฑ์ ์ ํํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ค์ํฉ๋๋ค. ๊ฐ๊ธฐ ๋ค๋ฅธ ์ฝ๋ฑ์ ์๋ก ๋ค๋ฅธ ๊ฐ์ ๊ณผ ์ฝ์ ์ ๊ฐ์ง๊ณ ์์ต๋๋ค:
- Opus: ๋งค์ฐ ๋ค์ฌ๋ค๋ฅํ๊ณ ๋๋ฆฌ ์ง์๋๋ ์ค๋์ค ์ฝ๋ฑ์ผ๋ก, ๋ฎ์ ๋นํธ๋ ์ดํธ์์๋ ๋ฐ์ด๋ ํ์ง๋ก ์ ๋ช ํฉ๋๋ค. WebRTC์ ๋๋ถ๋ถ ์ค๋์ค ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ถ์ฅ๋๋ ์ ํ์ ๋๋ค.
- VP8: WebRTC์์ ์ญ์ฌ์ ์ผ๋ก ์ค์ํ ๋ก์ดํฐ ํ๋ฆฌ ๋น๋์ค ์ฝ๋ฑ์ ๋๋ค. ์ฌ์ ํ ์ง์๋์ง๋ง, VP9๊ณผ AV1์ด ๋ ๋์ ์์ถ ํจ์จ์ ์ ๊ณตํฉ๋๋ค.
- VP9: VP8๋ณด๋ค ๋ ๋์ ์์ถ๋ฅ ์ ์ ๊ณตํ๋ ๋ ๋ฐ์ ๋ ๋ก์ดํฐ ํ๋ฆฌ ๋น๋์ค ์ฝ๋ฑ์ผ๋ก, ๋์ญํญ ์๋น๋ฅผ ์ค์ด๊ณ ํ์ง์ ํฅ์์ํต๋๋ค.
- H.264: ๋๋ฆฌ ๊ตฌํ๋ ๋น๋์ค ์ฝ๋ฑ์ผ๋ก, ๋ง์ ์ฅ์น์์ ํ๋์จ์ด ๊ฐ์์ด ์ง์๋ฉ๋๋ค. ๊ทธ๋ฌ๋ ๋ผ์ด์ ์ค๊ฐ ๋ณต์กํ ์ ์์ต๋๋ค. H.264๋ฅผ ์ฌ์ฉํ๊ธฐ๋ก ์ ํํ๋ค๋ฉด ๋ผ์ด์ ์ค ์๋ฌด๋ฅผ ์ดํดํ๋ ๊ฒ์ด ํ์์ ์ ๋๋ค.
- AV1: ๊ฐ์ฅ ์ต์ ์ ๊ฐ์ฅ ์ง๋ณด๋ ๋ก์ดํฐ ํ๋ฆฌ ๋น๋์ค ์ฝ๋ฑ์ผ๋ก, VP9๋ณด๋ค ํจ์ฌ ๋ ๋์ ์์ถ๋ฅ ์ ์ฝ์ํฉ๋๋ค. ๋ธ๋ผ์ฐ์ ์ง์์ด ์์ง ๋ฐ์ ์ค์ด์ง๋ง ๋น ๋ฅด๊ฒ ์ฆ๊ฐํ๊ณ ์์ต๋๋ค.
SDP(Session Description Protocol)์ ์ญํ
ํผ์ด๋ค์ด ์ค๋์ค์ ๋น๋์ค๋ฅผ ๊ตํํ๊ธฐ ์ ์, ๊ทธ๋ค์ ์ฌ์ฉํ ์ฝ๋ฑ์ ๋ํด ํฉ์ํด์ผ ํฉ๋๋ค. ์ด ํฉ์๋ SDP(Session Description Protocol)๋ฅผ ํตํด ์ด๋ฃจ์ด์ง๋๋ค. SDP๋ ์ง์๋๋ ์ฝ๋ฑ, ๋ฏธ๋์ด ์ ํ(์ค๋์ค, ๋น๋์ค), ์ ์ก ํ๋กํ ์ฝ ๋ฐ ๊ธฐํ ๊ด๋ จ ๋งค๊ฐ๋ณ์๋ฅผ ํฌํจํ์ฌ ๋ฉํฐ๋ฏธ๋์ด ์ธ์ ์ ํน์ฑ์ ์ค๋ช ํ๋ ํ ์คํธ ๊ธฐ๋ฐ ํ๋กํ ์ฝ์ ๋๋ค. ์ด๊ฒ์ ํผ์ด ๊ฐ์ ์ ์๋ผ๊ณ ์๊ฐํ ์ ์์ผ๋ฉฐ, ์ฌ๊ธฐ์ ๊ทธ๋ค์ ์์ ์ ๋ฅ๋ ฅ์ ์ ์ธํ๊ณ ์ํธ ํฉ์ ๊ฐ๋ฅํ ๊ตฌ์ฑ์ ํ์ํฉ๋๋ค.
WebRTC์์ SDP ๊ตํ์ ์ผ๋ฐ์ ์ผ๋ก ์๊ทธ๋๋ง ์๋ฒ์ ์ํด ์กฐ์ ๋๋ ์๊ทธ๋๋ง ํ๋ก์ธ์ค ์ค์ ๋ฐ์ํฉ๋๋ค. ์ด ํ๋ก์ธ์ค๋ ์ผ๋ฐ์ ์ผ๋ก ๋ค์ ๋จ๊ณ๋ฅผ ํฌํจํฉ๋๋ค:
- ์ ์ ์์ฑ: ํ ํผ์ด(์ ์์)๊ฐ ์์ ์ ๋ฏธ๋์ด ๊ธฐ๋ฅ๊ณผ ์ ํธํ๋ ์ฝ๋ฑ์ ์ค๋ช ํ๋ SDP ์ ์์ ์์ฑํฉ๋๋ค. ์ด ์ ์์ ๋ฌธ์์ด๋ก ์ธ์ฝ๋ฉ๋ฉ๋๋ค.
- ์๊ทธ๋๋ง: ์ ์์๋ ์๊ทธ๋๋ง ์๋ฒ๋ฅผ ํตํด ๋ค๋ฅธ ํผ์ด(์๋ต์)์๊ฒ SDP ์ ์์ ๋ณด๋ ๋๋ค.
- ์๋ต ์์ฑ: ์๋ต์๋ ์ ์์ ๋ฐ๊ณ ์ ์์์ ์ง์ํ๋ ์ฝ๋ฑ๊ณผ ๋งค๊ฐ๋ณ์๋ฅผ ์ ํํ์ฌ SDP ์๋ต์ ์์ฑํฉ๋๋ค.
- ์๊ทธ๋๋ง: ์๋ต์๋ ์๊ทธ๋๋ง ์๋ฒ๋ฅผ ํตํด ์ ์์์๊ฒ SDP ์๋ต์ ๋ค์ ๋ณด๋ ๋๋ค.
- ์ฐ๊ฒฐ ์ค์ : ์ด์ ๋ ํผ์ด ๋ชจ๋ WebRTC ์ฐ๊ฒฐ์ ์ค์ ํ๊ณ ๋ฏธ๋์ด๋ฅผ ๊ตํํ๋ ๋ฐ ํ์ํ SDP ์ ๋ณด๋ฅผ ๊ฐ๊ฒ ๋ฉ๋๋ค.
SDP ๊ตฌ์กฐ ๋ฐ ์ฃผ์ ์์ฑ
SDP๋ ๊ฐ ์ค์ ํ๋์ฉ ์๋ ์ผ๋ จ์ ์์ฑ-๊ฐ ์์ผ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค. ์ฝ๋ฑ ํ์์ ๊ฐ์ฅ ์ค์ํ ์์ฑ ์ค ์ผ๋ถ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- v= (ํ๋กํ ์ฝ ๋ฒ์ ): SDP ๋ฒ์ ์ ์ง์ ํฉ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก `v=0`์ ๋๋ค.
- o= (๋ฐ์ ์ง): ์ฌ์ฉ์ ์ด๋ฆ, ์ธ์ ID ๋ฐ ๋ฒ์ ์ ํฌํจํ์ฌ ์ธ์ ๋ฐ์ ์์ ๋ํ ์ ๋ณด๋ฅผ ํฌํจํฉ๋๋ค.
- s= (์ธ์ ์ด๋ฆ): ์ธ์ ์ ๋ํ ์ค๋ช ์ ์ ๊ณตํฉ๋๋ค.
- m= (๋ฏธ๋์ด ์ค๋ช ): ๋ฏธ๋์ด ์ ํ, ํฌํธ, ํ๋กํ ์ฝ ๋ฐ ํฌ๋งท ๋ชฉ๋ก์ ํฌํจํ์ฌ ๋ฏธ๋์ด ์คํธ๋ฆผ(์ค๋์ค ๋๋ ๋น๋์ค)์ ์ค๋ช ํฉ๋๋ค.
- a=rtpmap: (RTP ๋งต): ํ์ด๋ก๋ ์ ํ ๋ฒํธ๋ฅผ ํน์ ์ฝ๋ฑ, ํด๋ก ๋ ์ดํธ ๋ฐ ์ ํ์ ๋งค๊ฐ๋ณ์์ ๋งคํํฉ๋๋ค. ์๋ฅผ ๋ค์ด, `a=rtpmap:0 PCMU/8000`์ ํ์ด๋ก๋ ์ ํ 0์ด 8000 Hz์ ํด๋ก ๋ ์ดํธ๋ฅผ ๊ฐ์ง PCMU ์ค๋์ค ์ฝ๋ฑ์ ๋ํ๋์ ์๋ฏธํฉ๋๋ค.
- a=fmtp: (ํฌ๋งท ๋งค๊ฐ๋ณ์): ์ฝ๋ฑ๋ณ ๋งค๊ฐ๋ณ์๋ฅผ ์ง์ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, Opus์ ๊ฒฝ์ฐ `stereo` ๋ฐ `sprop-stereo` ๋งค๊ฐ๋ณ์๊ฐ ํฌํจ๋ ์ ์์ต๋๋ค.
- a=rtcp-fb: (RTCP ํผ๋๋ฐฑ): ํผ์ก ์ ์ด ๋ฐ ํ์ง ์ ์์ ์ค์ํ RTCP(Real-time Transport Control Protocol) ํผ๋๋ฐฑ ๋ฉ์ปค๋์ฆ ์ง์์ ๋ํ๋ ๋๋ค.
๋ค์์ Opus๋ฅผ ์ฐ์ ์ผ๋ก ํ๋ ์ค๋์ค์ ๋ํ SDP ์ ์์ ๊ฐ๋จํ ์์ ๋๋ค:
v=0 o=- 1234567890 2 IN IP4 127.0.0.1 s=WebRTC Session t=0 0 m=audio 9 UDP/TLS/RTP/SAVPF 111 0 a=rtpmap:111 opus/48000/2 a=fmtp:111 minptime=10;useinbandfec=1 a=rtpmap:0 PCMU/8000 a=ptime:20 a=maxptime:60
์ด ์์์:
- `m=audio 9 UDP/TLS/RTP/SAVPF 111 0`์ RTP/SAVPF ํ๋กํ ์ฝ์ ์ฌ์ฉํ๋ ์ค๋์ค ์คํธ๋ฆผ์ ๋ํ๋ด๋ฉฐ, ํ์ด๋ก๋ ์ ํ 111(Opus)๊ณผ 0(PCMU)์ ๊ฐ์ง๋๋ค.
- `a=rtpmap:111 opus/48000/2`๋ ํ์ด๋ก๋ ์ ํ 111์ 48000 Hz ํด๋ก ๋ ์ดํธ์ 2๊ฐ ์ฑ๋(์คํ ๋ ์ค)์ ๊ฐ์ง Opus ์ฝ๋ฑ์ผ๋ก ์ ์ํฉ๋๋ค.
- `a=rtpmap:0 PCMU/8000`์ ํ์ด๋ก๋ ์ ํ 0์ 8000 Hz ํด๋ก ๋ ์ดํธ(๋ชจ๋ ธ)๋ฅผ ๊ฐ์ง PCMU ์ฝ๋ฑ์ผ๋ก ์ ์ํฉ๋๋ค.
ํ๋ก ํธ์๋ ์ฝ๋ฑ ์ ํ ๊ธฐ์
๋ธ๋ผ์ฐ์ ๊ฐ ๋๋ถ๋ถ์ SDP ์์ฑ ๋ฐ ํ์์ ์ฒ๋ฆฌํ์ง๋ง, ํ๋ก ํธ์๋ ๊ฐ๋ฐ์๋ ์ฝ๋ฑ ์ ํ ๊ณผ์ ์ ์ํฅ์ ๋ฏธ์น ์ ์๋ ๋ช ๊ฐ์ง ๊ธฐ์ ์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
1. ๋ฏธ๋์ด ์ ์ฝ ์กฐ๊ฑด
`getUserMedia()`๋ฅผ ํธ์ถํ๊ฑฐ๋ `RTCPeerConnection`์ ์์ฑํ ๋ ๋ฏธ๋์ด ์ ์ฝ ์กฐ๊ฑด์ ํตํด ํ๋ก ํธ์๋์์ ์ฝ๋ฑ ์ ํ์ ์ํฅ์ ๋ฏธ์น๋ ๊ฒ์ด ์ฃผ์ ๋ฐฉ๋ฒ์ ๋๋ค. ๋ฏธ๋์ด ์ ์ฝ ์กฐ๊ฑด์ ์ฌ์ฉํ๋ฉด ์ค๋์ค ๋ฐ ๋น๋์ค ํธ๋์ ๋ํด ์ํ๋ ์์ฑ์ ์ง์ ํ ์ ์์ต๋๋ค. ํ์ค ์ ์ฝ ์กฐ๊ฑด์์ ์ฝ๋ฑ ์ด๋ฆ์ ์ง์ ์ง์ ํ ์๋ ์์ง๋ง, ํน์ ์ฝ๋ฑ์ ์ ๋ฆฌํ ๋ค๋ฅธ ์์ฑ์ ์ง์ ํ์ฌ ์ ํ์ ์ํฅ์ ์ค ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, ๋ ๋์ ํ์ง์ ์ค๋์ค๋ฅผ ์ ํธํ๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ ์ฝ ์กฐ๊ฑด์ ์ฌ์ฉํ ์ ์์ต๋๋ค:
const constraints = {
audio: {
echoCancellation: true,
noiseSuppression: true,
sampleRate: 48000, // Higher sample rate favors codecs like Opus
channelCount: 2, // Stereo audio
},
video: {
width: { min: 640, ideal: 1280, max: 1920 },
height: { min: 480, ideal: 720, max: 1080 },
frameRate: { min: 24, ideal: 30, max: 60 },
}
};
navigator.mediaDevices.getUserMedia(constraints)
.then(stream => { /* ... */ })
.catch(error => { console.error("์ฌ์ฉ์ ๋ฏธ๋์ด ๊ฐ์ ธ์ค๊ธฐ ์ค๋ฅ:", error); });
์ค๋์ค์ ๋ํด ๋ ๋์ `sampleRate`(48000 Hz)๋ฅผ ์ง์ ํจ์ผ๋ก์จ, PCMU/PCMA(์ข ์ข 8000 Hz ์ฌ์ฉ)์ ๊ฐ์ ์ค๋๋ ์ฝ๋ฑ๋ณด๋ค ์ผ๋ฐ์ ์ผ๋ก ๋ ๋์ ์ํ ๋ ์ดํธ์์ ์๋ํ๋ Opus์ ๊ฐ์ ์ฝ๋ฑ์ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ํํ๋๋ก ๊ฐ์ ์ ์ผ๋ก ์ ๋ํ ์ ์์ต๋๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก `width`, `height`, `frameRate`์ ๊ฐ์ ๋น๋์ค ์ ์ฝ ์กฐ๊ฑด์ ์ง์ ํ๋ฉด ๋ธ๋ผ์ฐ์ ์ ๋น๋์ค ์ฝ๋ฑ ์ ํ์ ์ํฅ์ ์ค ์ ์์ต๋๋ค.
๋ธ๋ผ์ฐ์ ๊ฐ ์ด๋ฌํ ์ ์ฝ ์กฐ๊ฑด์ ์ ํํ ์ถฉ์กฑํ ๊ฒ์ด๋ผ๊ณ *๋ณด์ฅ*๋์ง๋ ์๋๋ค๋ ์ ์ ์ ์ํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์ฌ์ฉ ๊ฐ๋ฅํ ํ๋์จ์ด ๋ฐ ์ฝ๋ฑ ์ง์์ ๊ธฐ๋ฐ์ผ๋ก ์ต์ ์ ๋คํด ์ผ์น์ํค๋ ค๊ณ ๋ ธ๋ ฅํ ๊ฒ์ ๋๋ค. `ideal` ๊ฐ์ ์ ํธํ๋ ๊ฒ์ ๋ํ ํํธ๋ฅผ ๋ธ๋ผ์ฐ์ ์ ์ ๊ณตํ๋ ๋ฐ๋ฉด, `min`๊ณผ `max`๋ ํ์ฉ ๊ฐ๋ฅํ ๋ฒ์๋ฅผ ์ ์ํฉ๋๋ค.
2. SDP ์กฐ์(๊ณ ๊ธ)
๋ ์ธ๋ฐํ ์ ์ด๋ฅผ ์ํด, ๊ตํ๋๊ธฐ ์ ์ SDP ์ ์ ๋ฐ ์๋ต ๋ฌธ์์ด์ ์ง์ ์กฐ์ํ ์ ์์ต๋๋ค. ์ด ๊ธฐ์ ์ ๊ณ ๊ธ ๊ธฐ์ ๋ก ๊ฐ์ฃผ๋๋ฉฐ SDP ๊ตฌ๋ฌธ์ ๋ํ ์ฒ ์ ํ ์ดํด๊ฐ ํ์ํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ด๋ฅผ ํตํด ์ฝ๋ฑ ์์๋ฅผ ๋ณ๊ฒฝํ๊ฑฐ๋, ์์น ์๋ ์ฝ๋ฑ์ ์ ๊ฑฐํ๊ฑฐ๋, ์ฝ๋ฑ๋ณ ๋งค๊ฐ๋ณ์๋ฅผ ์์ ํ ์ ์์ต๋๋ค.
์ค์ํ ๋ณด์ ๊ณ ๋ ค ์ฌํญ: SDP๋ฅผ ์์ ํ๋ ๊ฒ์ ์ ์คํ๊ฒ ์ํํ์ง ์์ผ๋ฉด ์ ์ฌ์ ์ผ๋ก ๋ณด์ ์ทจ์ฝ์ ์ ์ ๋ฐํ ์ ์์ต๋๋ค. ์ฃผ์ ๊ณต๊ฒฉ์ด๋ ๊ธฐํ ๋ณด์ ์ํ์ ๋ฐฉ์งํ๊ธฐ ์ํด ํญ์ ๋ชจ๋ SDP ์์ ์ ๊ฒ์ฆํ๊ณ ์ด๊ท ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค.
๋ค์์ SDP ๋ฌธ์์ด์์ ์ฝ๋ฑ ์์๋ฅผ ๋ณ๊ฒฝํ์ฌ ํน์ ์ฝ๋ฑ(์: ์ค๋์ค์ฉ Opus)์ ์ฐ์ ์์๋ก ์ง์ ํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ฃผ๋ JavaScript ํจ์์ ๋๋ค:
function prioritizeCodec(sdp, codec, mediaType) {
const lines = sdp.split('\n');
let rtpmapLine = null;
let fmtpLine = null;
let rtcpFbLines = [];
let mediaDescriptionLineIndex = -1;
// Find the codec's rtpmap, fmtp, and rtcp-fb lines and the media description line.
for (let i = 0; i < lines.length; i++) {
if (lines[i].startsWith('m=' + mediaType)) {
mediaDescriptionLineIndex = i;
} else if (lines[i].startsWith('a=rtpmap:') && lines[i].includes(codec + '/')) {
rtpmapLine = lines[i];
} else if (lines[i].startsWith('a=fmtp:') && lines[i].includes(codec)) {
fmtpLine = lines[i];
} else if (lines[i].startsWith('a=rtcp-fb:') && rtpmapLine && lines[i].includes(rtpmapLine.split(' ')[1])){
rtcpFbLines.push(lines[i]);
}
}
if (rtpmapLine) {
// Remove the codec from the format list in the media description line.
const mediaDescriptionLine = lines[mediaDescriptionLineIndex];
const formatList = mediaDescriptionLine.split(' ')[3].split(' ');
const codecPayloadType = rtpmapLine.split(' ')[1];
const newFormatList = formatList.filter(pt => pt !== codecPayloadType);
lines[mediaDescriptionLineIndex] = mediaDescriptionLine.replace(formatList.join(' '), newFormatList.join(' '));
// Add the codec to the beginning of the format list
lines[mediaDescriptionLineIndex] = lines[mediaDescriptionLineIndex].replace('m=' + mediaType, 'm=' + mediaType + ' ' + codecPayloadType);
// Move the rtpmap, fmtp, and rtcp-fb lines to be after the media description line.
lines.splice(mediaDescriptionLineIndex + 1, 0, rtpmapLine);
if (fmtpLine) {
lines.splice(mediaDescriptionLineIndex + 2, 0, fmtpLine);
}
for(let i = 0; i < rtcpFbLines.length; i++) {
lines.splice(mediaDescriptionLineIndex + 3 + i, 0, rtcpFbLines[i]);
}
// Remove the original lines
let indexToRemove = lines.indexOf(rtpmapLine, mediaDescriptionLineIndex + 1); // Start searching after insertion
if (indexToRemove > -1) {
lines.splice(indexToRemove, 1);
}
if (fmtpLine) {
indexToRemove = lines.indexOf(fmtpLine, mediaDescriptionLineIndex + 1); // Start searching after insertion
if (indexToRemove > -1) {
lines.splice(indexToRemove, 1);
}
}
for(let i = 0; i < rtcpFbLines.length; i++) {
indexToRemove = lines.indexOf(rtcpFbLines[i], mediaDescriptionLineIndex + 1); // Start searching after insertion
if (indexToRemove > -1) {
lines.splice(indexToRemove, 1);
}
}
return lines.join('\n');
} else {
return sdp;
}
}
// ์ฌ์ฉ ์์:
const pc = new RTCPeerConnection();
pc.createOffer()
.then(offer => {
let sdp = offer.sdp;
console.log("์๋ณธ SDP:\n", sdp);
let modifiedSdp = prioritizeCodec(sdp, 'opus', 'audio');
console.log("์์ ๋ SDP:\n", modifiedSdp);
offer.sdp = modifiedSdp; // ์์ ๋ SDP๋ก ์ ์ ์
๋ฐ์ดํธ
return pc.setLocalDescription(offer);
})
.then(() => { /* ... */ })
.catch(error => { console.error("์ ์ ์์ฑ ์ค๋ฅ:", error); });
์ด ํจ์๋ SDP ๋ฌธ์์ด์ ํ์ฑํ์ฌ ์ง์ ๋ ์ฝ๋ฑ(์: `opus`)๊ณผ ๊ด๋ จ๋ ์ค์ ์๋ณํ๊ณ , ํด๋น ์ค์ `m=`(๋ฏธ๋์ด ์ค๋ช ) ์น์ ์ ๋งจ ์๋ก ์ด๋์์ผ ํด๋น ์ฝ๋ฑ์ ์ฐ์ ์์๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๋์ ๋๋ค. ๋ํ ์ค๋ณต์ ํผํ๊ธฐ ์ํด ํฌ๋งท ๋ชฉ๋ก์ ์๋ ์์น์์ ์ฝ๋ฑ์ ์ ๊ฑฐํฉ๋๋ค. ์ด ์์ ์ฌํญ์ ์ ์์ผ๋ก ๋ก์ปฌ ์ค๋ช ์ ์ค์ ํ๊ธฐ *์ ์* ์ ์ฉํด์ผ ํ๋ค๋ ๊ฒ์ ๊ธฐ์ตํ์ญ์์ค.
์ด ํจ์๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ๋ค์์ ์ํํฉ๋๋ค:
- `RTCPeerConnection`์ ์์ฑํฉ๋๋ค.
- `createOffer()`๋ฅผ ํธ์ถํ์ฌ ์ด๊ธฐ SDP ์ ์์ ์์ฑํฉ๋๋ค.
- `prioritizeCodec()`๋ฅผ ํธ์ถํ์ฌ ์ ํธํ๋ ์ฝ๋ฑ์ ์ฐ์ ์์๋ฅผ ์ง์ ํ๋๋ก SDP ๋ฌธ์์ด์ ์์ ํฉ๋๋ค.
- ์์ ๋ ๋ฌธ์์ด๋ก ์ ์์ SDP๋ฅผ ์ ๋ฐ์ดํธํฉ๋๋ค.
- `setLocalDescription()`์ ํธ์ถํ์ฌ ์์ ๋ ์ ์์ ๋ก์ปฌ ์ค๋ช ์ผ๋ก ์ค์ ํฉ๋๋ค.
๋์ผํ ์์น์ด ์๋ต SDP์๋ ์ ์ฉ๋ ์ ์์ผ๋ฉฐ, `createAnswer()` ๋ฉ์๋์ `setRemoteDescription()`์ ์ ์ ํ๊ฒ ์ฌ์ฉํฉ๋๋ค.
3. ํธ๋์๋ฒ ๊ธฐ๋ฅ (์ต์ ์ ๊ทผ ๋ฐฉ์)
`RTCRtpTransceiver` API๋ WebRTC์์ ์ฝ๋ฑ ๋ฐ ๋ฏธ๋์ด ์คํธ๋ฆผ์ ๊ด๋ฆฌํ๋ ๋ ํ๋์ ์ด๊ณ ๊ตฌ์กฐํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ํธ๋์๋ฒ๋ ๋ฏธ๋์ด ์ก์์ ์ ์บก์ํํ์ฌ ๋ฏธ๋์ด ํ๋ฆ์ ๋ฐฉํฅ(sendonly, recvonly, sendrecv, inactive)์ ์ ์ดํ๊ณ ์ํ๋ ์ฝ๋ฑ ์ ํธ๋๋ฅผ ์ง์ ํ ์ ์๋๋ก ํฉ๋๋ค.
๊ทธ๋ฌ๋ ํธ๋์๋ฒ๋ฅผ ํตํ ์ง์ ์ ์ธ ์ฝ๋ฑ ์กฐ์์ ์์ง ๋ชจ๋ ๋ธ๋ผ์ฐ์ ์์ ์์ ํ ํ์คํ๋์ง ์์์ต๋๋ค. ๊ฐ์ฅ ์ ๋ขฐํ ์ ์๋ ์ ๊ทผ ๋ฐฉ์์ ์ต๋์ ํธํ์ฑ์ ์ํด ํธ๋์๋ฒ ์ ์ด์ SDP ์กฐ์์ ๊ฒฐํฉํ๋ ๊ฒ์ ๋๋ค.
๋ค์์ ํธ๋์๋ฒ๋ฅผ SDP ์กฐ์๊ณผ ํจ๊ป ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ํ ์์ ๋๋ค (SDP ์กฐ์ ๋ถ๋ถ์ ์ ์์ ์ ์ฌํฉ๋๋ค):
const pc = new RTCPeerConnection();
// ์ค๋์ค์ฉ ํธ๋์๋ฒ ์ถ๊ฐ
const audioTransceiver = pc.addTransceiver('audio');
// ๋ก์ปฌ ์คํธ๋ฆผ์ ๊ฐ์ ธ์ ํธ๋์๋ฒ์ ํธ๋ ์ถ๊ฐ
navigator.mediaDevices.getUserMedia({ audio: true, video: false })
.then(stream => {
stream.getTracks().forEach(track => {
audioTransceiver.addTrack(track, stream);
});
// ์ด์ ๊ณผ ๊ฐ์ด SDP ์ ์ ์์ฑ ๋ฐ ์์
pc.createOffer()
.then(offer => {
let sdp = offer.sdp;
let modifiedSdp = prioritizeCodec(sdp, 'opus', 'audio');
offer.sdp = modifiedSdp;
return pc.setLocalDescription(offer);
})
.then(() => { /* ... */ })
.catch(error => { console.error("์ ์ ์์ฑ ์ค๋ฅ:", error); });
})
.catch(error => { console.error("์ฌ์ฉ์ ๋ฏธ๋์ด ๊ฐ์ ธ์ค๊ธฐ ์ค๋ฅ:", error); });
์ด ์์์๋ ์ค๋์ค ํธ๋์๋ฒ๋ฅผ ๋ง๋ค๊ณ ๋ก์ปฌ ์คํธ๋ฆผ์ ์ค๋์ค ํธ๋์ ์ถ๊ฐํฉ๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ ๋ฏธ๋์ด ํ๋ฆ์ ๋ํ ๋ ๋ง์ ์ ์ด๋ฅผ ์ ๊ณตํ๋ฉฐ, ํนํ ์ฌ๋ฌ ๋ฏธ๋์ด ์คํธ๋ฆผ์ ๋ค๋ฃฐ ๋ ์ฝ๋ฑ์ ๊ด๋ฆฌํ๋ ๋ ๊ตฌ์กฐํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
๋ธ๋ผ์ฐ์ ํธํ์ฑ ๊ณ ๋ ค ์ฌํญ
์ฝ๋ฑ ์ง์์ ๋ธ๋ผ์ฐ์ ๋ง๋ค ๋ค๋ฆ ๋๋ค. Opus๋ ์ค๋์ค์์ ๋๋ฆฌ ์ง์๋์ง๋ง, ๋น๋์ค ์ฝ๋ฑ ์ง์์ ๋ ๋จํธ์ ์ผ ์ ์์ต๋๋ค. ๋ค์์ ๋ธ๋ผ์ฐ์ ํธํ์ฑ์ ๋ํ ์ผ๋ฐ์ ์ธ ๊ฐ์์ ๋๋ค:
- Opus: ๋ชจ๋ ์ฃผ์ ๋ธ๋ผ์ฐ์ (Chrome, Firefox, Safari, Edge)์์ ๋ฐ์ด๋ ์ง์์ ์ ๊ณตํฉ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก WebRTC์ ์ ํธ๋๋ ์ค๋์ค ์ฝ๋ฑ์ ๋๋ค.
- VP8: ์ง์์ ์ํธํ์ง๋ง, ์ผ๋ฐ์ ์ผ๋ก VP9 ๋ฐ AV1๋ก ๋์ฒด๋๊ณ ์์ต๋๋ค.
- VP9: Chrome, Firefox ๋ฐ ์ต์ ๋ฒ์ ์ Edge์ Safari์์ ์ง์๋ฉ๋๋ค.
- H.264: ๋๋ถ๋ถ์ ๋ธ๋ผ์ฐ์ ์์ ์ง์๋๋ฉฐ, ์ข ์ข ํ๋์จ์ด ๊ฐ์์ด ์ง์๋์ด ๋๋ฆฌ ์ฌ์ฉ๋๋ ์ ํ์ง์ ๋๋ค. ๊ทธ๋ฌ๋ ๋ผ์ด์ ์ค๊ฐ ๋ฌธ์ ๊ฐ ๋ ์ ์์ต๋๋ค.
- AV1: ์ง์์ด ๋น ๋ฅด๊ฒ ์ฆ๊ฐํ๊ณ ์์ต๋๋ค. Chrome, Firefox ๋ฐ ์ต์ ๋ฒ์ ์ Edge์ Safari์์ AV1์ ์ง์ํฉ๋๋ค. ์ต๊ณ ์ ์์ถ ํจ์จ์ ์ ๊ณตํ์ง๋ง ๋ ๋ง์ ์ฒ๋ฆฌ ๋ฅ๋ ฅ์ด ํ์ํ ์ ์์ต๋๋ค.
ํธํ์ฑ๊ณผ ์ต์ ์ ์ฑ๋ฅ์ ๋ณด์ฅํ๊ธฐ ์ํด ๋ค์ํ ๋ธ๋ผ์ฐ์ ์ ์ฅ์น์์ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ ์คํธํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๊ธฐ๋ฅ ๊ฐ์ง๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์์ ๋ธ๋ผ์ฐ์ ์์ ์ง์ํ๋ ์ฝ๋ฑ์ ํ์ธํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, `RTCRtpSender.getCapabilities()` ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ AV1 ์ง์ ์ฌ๋ถ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค:
if (RTCRtpSender.getCapabilities('video').codecs.find(codec => codec.mimeType === 'video/AV1')) {
console.log('AV1์ด ์ง์๋ฉ๋๋ค!');
} else {
console.log('AV1์ด ์ง์๋์ง ์์ต๋๋ค.');
}
๊ฐ์ง๋ ๊ธฐ๋ฅ์ ๋ฐ๋ผ ์ฝ๋ฑ ์ ํธ๋๋ฅผ ์กฐ์ ํ์ฌ ๊ฐ ์ฌ์ฉ์์๊ฒ ์ต์์ ๊ฒฝํ์ ์ ๊ณตํ์ญ์์ค. ํต์ ์ด ํญ์ ๊ฐ๋ฅํ๋๋ก (์: VP9 ๋๋ AV1์ด ์ง์๋์ง ์๋ ๊ฒฝ์ฐ H.264 ์ฌ์ฉ) ๋์ฒด ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํ์ญ์์ค.
ํ๋ก ํธ์๋ WebRTC ์ฝ๋ฑ ์ ํ์ ์ํ ๋ชจ๋ฒ ์ฌ๋ก
WebRTC ์ ํ๋ฆฌ์ผ์ด์ ์ฉ ์ฝ๋ฑ์ ์ ํํ ๋ ๋ฐ๋ผ์ผ ํ ๋ช ๊ฐ์ง ๋ชจ๋ฒ ์ฌ๋ก๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ค๋์ค์๋ Opus ์ฐ์ ์ฌ์ฉ: Opus๋ ๋ฎ์ ๋นํธ๋ ์ดํธ์์ ๋ฐ์ด๋ ์ค๋์ค ํ์ง์ ์ ๊ณตํ๋ฉฐ ๋๋ฆฌ ์ง์๋ฉ๋๋ค. ์ค๋์ค ํต์ ์ ์ํ ๊ธฐ๋ณธ ์ ํ์ด ๋์ด์ผ ํฉ๋๋ค.
- ๋น๋์ค์๋ VP9 ๋๋ AV1 ๊ณ ๋ ค: ์ด ๋ก์ดํฐ ํ๋ฆฌ ์ฝ๋ฑ๋ค์ VP8๋ณด๋ค ๋ ๋์ ์์ถ ํจ์จ์ ์ ๊ณตํ๋ฉฐ ๋์ญํญ ์๋น๋ฅผ ํฌ๊ฒ ์ค์ผ ์ ์์ต๋๋ค. ๋ธ๋ผ์ฐ์ ์ง์์ด ์ถฉ๋ถํ๋ค๋ฉด ์ด ์ฝ๋ฑ๋ค์ ์ฐ์ ์ ์ผ๋ก ์ฌ์ฉํ์ญ์์ค.
- H.264๋ฅผ ๋์ฒด ์๋จ์ผ๋ก ์ฌ์ฉ: H.264๋ ๋๋ฆฌ ์ง์๋๋ฉฐ ์ข ์ข ํ๋์จ์ด ๊ฐ์์ด ์ง์๋ฉ๋๋ค. VP9 ๋๋ AV1์ ์ฌ์ฉํ ์ ์์ ๋ ๋์ฒด ์ต์ ์ผ๋ก ์ฌ์ฉํ์ญ์์ค. ๋ผ์ด์ ์ค ์ํฅ์ ์ธ์งํด์ผ ํฉ๋๋ค.
- ๊ธฐ๋ฅ ๊ฐ์ง ๊ตฌํ: `RTCRtpSender.getCapabilities()`๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์ํ ์ฝ๋ฑ์ ๋ํ ๋ธ๋ผ์ฐ์ ์ง์์ ๊ฐ์งํ์ญ์์ค.
- ๋คํธ์ํฌ ์กฐ๊ฑด์ ์ ์: ๋คํธ์ํฌ ์กฐ๊ฑด์ ๋ฐ๋ผ ์ฝ๋ฑ๊ณผ ๋นํธ๋ ์ดํธ๋ฅผ ์กฐ์ ํ๋ ๋ฉ์ปค๋์ฆ์ ๊ตฌํํ์ญ์์ค. RTCP ํผ๋๋ฐฑ์ ํจํท ์์ค ๋ฐ ์ง์ฐ ์๊ฐ์ ๋ํ ์ ๋ณด๋ฅผ ์ ๊ณตํ์ฌ ์ต์ ์ ํ์ง์ ์ ์งํ๊ธฐ ์ํด ์ฝ๋ฑ์ด๋ ๋นํธ๋ ์ดํธ๋ฅผ ๋์ ์ผ๋ก ์กฐ์ ํ ์ ์๊ฒ ํด์ค๋๋ค.
- ๋ฏธ๋์ด ์ ์ฝ ์กฐ๊ฑด ์ต์ ํ: ๋ฏธ๋์ด ์ ์ฝ ์กฐ๊ฑด์ ์ฌ์ฉํ์ฌ ๋ธ๋ผ์ฐ์ ์ ์ฝ๋ฑ ์ ํ์ ์ํฅ์ ์ฃผ๋, ๊ทธ ํ๊ณ๋ฅผ ์ผ๋์ ๋์ญ์์ค.
- SDP ์์ ์ฌํญ ์ด๊ท ์ฒ๋ฆฌ: SDP๋ฅผ ์ง์ ์กฐ์ํ๋ ๊ฒฝ์ฐ, ๋ณด์ ์ทจ์ฝ์ ์ ๋ฐฉ์งํ๊ธฐ ์ํด ์์ ์ฌํญ์ ์ฒ ์ ํ ๊ฒ์ฆํ๊ณ ์ด๊ท ์ฒ๋ฆฌํ์ญ์์ค.
- ์ฒ ์ ํ ํ ์คํธ: ๋ค์ํ ๋ธ๋ผ์ฐ์ , ์ฅ์น ๋ฐ ๋คํธ์ํฌ ์กฐ๊ฑด์์ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ ์คํธํ์ฌ ํธํ์ฑ๊ณผ ์ต์ ์ ์ฑ๋ฅ์ ๋ณด์ฅํ์ญ์์ค. Wireshark์ ๊ฐ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ SDP ๊ตํ์ ๋ถ์ํ๊ณ ์ฌ๋ฐ๋ฅธ ์ฝ๋ฑ์ด ์ฌ์ฉ๋๊ณ ์๋์ง ํ์ธํ์ญ์์ค.
- ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง: WebRTC ํต๊ณ API(`getStats()`)๋ฅผ ์ฌ์ฉํ์ฌ ๋นํธ๋ ์ดํธ, ํจํท ์์ค ๋ฐ ์ง์ฐ ์๊ฐ์ ํฌํจํ WebRTC ์ฐ๊ฒฐ ์ฑ๋ฅ์ ๋ชจ๋ํฐ๋งํ์ญ์์ค. ์ด ๋ฐ์ดํฐ๋ ์ฑ๋ฅ ๋ณ๋ชฉ ํ์์ ์๋ณํ๊ณ ํด๊ฒฐํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
- Simulcast/SVC ๊ณ ๋ ค: ๋ค์๊ฐ ํตํ๋ ๋ค์ํ ๋คํธ์ํฌ ์กฐ๊ฑด์ด ์๋ ์๋๋ฆฌ์ค์์๋ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ ํ๊ธฐ ์ํด Simulcast(๋์ผํ ๋น๋์ค ์คํธ๋ฆผ์ ์ฌ๋ฌ ๋ฒ์ ์ ๋ค๋ฅธ ํด์๋ ๋ฐ ๋นํธ๋ ์ดํธ๋ก ์ ์ก) ๋๋ SVC(Scalable Video Coding, ๋น๋์ค๋ฅผ ์ฌ๋ฌ ๊ณ์ธต์ผ๋ก ์ธ์ฝ๋ฉํ๋ ๋ ๊ณ ๊ธ ๊ธฐ์ ) ์ฌ์ฉ์ ๊ณ ๋ คํ์ญ์์ค.
๊ฒฐ๋ก
WebRTC ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ํฉํ ์ฝ๋ฑ์ ์ ํํ๋ ๊ฒ์ ์ฌ์ฉ์์๊ฒ ๊ณ ํ์ง ์ค์๊ฐ ํต์ ๊ฒฝํ์ ๋ณด์ฅํ๋ ์ค์ํ ๋จ๊ณ์ ๋๋ค. SDP์ ์๋ฆฌ๋ฅผ ์ดํดํ๊ณ , ๋ฏธ๋์ด ์ ์ฝ ์กฐ๊ฑด ๋ฐ SDP ์กฐ์ ๊ธฐ์ ์ ํ์ฉํ๋ฉฐ, ๋ธ๋ผ์ฐ์ ํธํ์ฑ์ ๊ณ ๋ คํ๊ณ , ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ฐ๋ฆ์ผ๋ก์จ WebRTC ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฑ๋ฅ, ์์ ์ฑ ๋ฐ ๊ธ๋ก๋ฒ ๋๋ฌ ๋ฒ์๋ฅผ ์ต์ ํํ ์ ์์ต๋๋ค. ์ค๋์ค์๋ Opus๋ฅผ ์ฐ์ ์ ์ผ๋ก ์ฌ์ฉํ๊ณ , ๋น๋์ค์๋ VP9 ๋๋ AV1์ ๊ณ ๋ คํ๋ฉฐ, H.264๋ฅผ ๋์ฒด ์๋จ์ผ๋ก ์ฌ์ฉํ๊ณ , ํญ์ ๋ค์ํ ํ๋ซํผ๊ณผ ๋คํธ์ํฌ ์กฐ๊ฑด์์ ์ฒ ์ ํ ํ ์คํธํ๋ ๊ฒ์ ๊ธฐ์ตํ์ญ์์ค. WebRTC ๊ธฐ์ ์ด ๊ณ์ ๋ฐ์ ํจ์ ๋ฐ๋ผ ์ต์ ์ฝ๋ฑ ๊ฐ๋ฐ ๋ฐ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ฅ์ ๋ํ ์ ๋ณด๋ฅผ ์ ์งํ๋ ๊ฒ์ ์ต์ฒจ๋จ ์ค์๊ฐ ํต์ ์๋ฃจ์ ์ ์ ๊ณตํ๋ ๋ฐ ํ์์ ์ ๋๋ค.